// LoadByFastHttp project main.go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"sync"
	"syscall"
	"time"

	"github.com/myzhan/boomer"
	"github.com/valyala/fasthttp"
)

//全局变量
//连接设置
var (
	client *fasthttp.Client = &fasthttp.Client{
		MaxConnsPerHost: 46384,
		ReadTimeout:     5 * time.Second,
		WriteTimeout:    5 * time.Second,
	}
)

/*
//内容
var postBody []byte

//请求方法
var method string

//url地址
var url string

//超时时间
var timeout time.Duration

//请求格式
var contentType string

//是否保持长链接
var disableKeepalive bool

//期望状态码
var expect_code int

var disable_response bool

var task_name string

var expect_string string
*/
//请求任务
type TaskData struct {
	Task_name     string
	Request_datas []RequestBodyData
}

//请求参数
type RequestBodyData struct {
	Method           string
	Url              string
	PostBody         string
	ContentType      string
	DisableKeepalive bool
	Expect_code      int
	Disable_response bool
	Expect_string    string
	Header_datas     []RequestHeaderData
}

//请求header
type RequestHeaderData struct {
	HeaderName  string
	HeaderValue string
}

//定义一个全局变量，用来存放测试的数据
var TD TaskData

//boomer的启动程序

//一次性去执行多个请求的内容
func httpMoreRequest(td TaskData) {
	for _, t := range td.Request_datas {
		//log.Println("=============")
		httpRequest(t, td.Task_name)
	}
}

//获取测试内容去执行
func httpRequest(reqData RequestBodyData, task_name string) {
	//创建一个request对象
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)
	//创建一个response对象
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)

	//设置请求相关方法以及Header
	req.Header.SetMethod(reqData.Method)
	req.Header.SetContentType(reqData.ContentType)

	if reqData.DisableKeepalive {
		req.Header.SetConnectionClose()
	}

	for _, head := range reqData.Header_datas {
		req.Header.Add(head.HeaderName, head.HeaderValue)
	}

	req.SetRequestURI(reqData.Url)
	req.SetBody([]byte(reqData.PostBody))

	//发送请求，并记录发送的开始、结束时间

	startTime := time.Now()
	err := client.Do(req, resp)
	elapsed := time.Since(startTime)

	//处理公共异常
	if err != nil {
		switch err {
		case fasthttp.ErrTimeout:
			//log.Println("ErrTimeout")
			globalBoomer.RecordFailure(task_name, "timeout", elapsed.Nanoseconds()/int64(time.Millisecond), err.Error())
		case fasthttp.ErrNoFreeConns:
			//log.Println("ErrNoFreeConns")
			globalBoomer.RecordFailure(task_name, "connections all busy", elapsed.Nanoseconds()/int64(time.Millisecond), err.Error())
		default:
			//log.Println("default")
			globalBoomer.RecordFailure(task_name, "unknown", elapsed.Nanoseconds()/int64(time.Millisecond), err.Error())
		}

		return
	}
	if resp.StatusCode() == reqData.Expect_code {
		resStr := string(resp.Body())
		if strings.Contains(reqData.Expect_string, resStr) {
			//log.Println("expect_string")
			globalBoomer.RecordFailure(task_name, string(resp.Body()), elapsed.Nanoseconds()/int64(time.Millisecond), string(resp.Body()))

		} else {
			//log.Println("expect_string fail")
			globalBoomer.RecordSuccess(task_name, strconv.Itoa(resp.StatusCode()), elapsed.Nanoseconds()/int64(time.Millisecond), int64(len(resp.Body())))
		}

	} else {
		//log.Println("StatusCode")
		globalBoomer.RecordFailure(task_name, strconv.Itoa(resp.StatusCode()), elapsed.Nanoseconds()/int64(time.Millisecond), string(resp.Body()))

	}

	if reqData.Disable_response {

		log.Println(string(resp.Body()))
	}

}

//使用fasthttp发出请求，并且增加了自定义
func httpSimple(method string, url string, postBody []byte, contentType string) []byte {
	//创建一个request对象
	req := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(req)
	//创建一个response对象
	resp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(resp)
	//设置请求相关方法以及Header
	req.Header.SetMethod(method)
	req.Header.SetContentType(contentType)
	req.SetRequestURI(url)
	req.SetBody(postBody)
	//发送请求，并记录发送的开始、结束时间
	err := client.Do(req, resp)
	//处理公共异常
	if err != nil {
		switch err {
		case fasthttp.ErrTimeout:
			log.Println("ErrTimeout")

		case fasthttp.ErrNoFreeConns:
			log.Println("ErrNoFreeConns")
		default:
			log.Println("fail")
		}
		return []byte("")
	}

	return resp.Body()

}

//将接口返回的数据进行解析
func initRequestData(jsonByte []byte) TaskData {
	//bString := []byte(jsonString)
	var td TaskData
	//log.Println("================")
	//log.Println(string(jsonByte))
	err := json.Unmarshal(jsonByte, &td)
	if err != nil {
		log.Println(err)
	}

	return td

}

func boomerWork() {
	httpMoreRequest(TD)
}

func waitForQuit() {
	wg := sync.WaitGroup{}
	wg.Add(1)

	quitByMe := false
	go func() {
		c := make(chan os.Signal)
		signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
		<-c
		quitByMe = true
		globalBoomer.Quit()
		wg.Done()
	}()

	boomer.Events.Subscribe("boomer:quit", func() {
		if !quitByMe {
			wg.Done()
		}
	})

	wg.Wait()
}

var master_ip = "10.201.3.132"
var master_port = 5558
var webPort = 49999

var globalBoomer = boomer.NewBoomer(master_ip, master_port)

//var webPort = 8089

func main() {

	//启动时去读取测试案例，并赋给全局变量
	boomer.Events.Subscribe("boomer:hatch", func(workers int, hatchRate float64) {
		log.Println("==========================================================================Start")
		url := fmt.Sprintf("http://127.0.0.1:9012/load/task?master_ip=%s&master_port=%v", master_ip, master_port)
		log.Println(url)

		d := httpSimple("GET", url, []byte(""), "application/json")
		TD = initRequestData(d)
		if TD.Task_name == "" {
			return
		}
		log.Println(TD)
		log.Println("==========================================================================Get Msg")

	})

	//停止时去更新测试结果
	boomer.Events.Subscribe("boomer:stop", func() {
		//获取停止时的结果
		if TD.Task_name == "" {
			return
		}
		rurl := fmt.Sprintf("http://%s:%v/stats/requests", master_ip, webPort)
		log.Println(rurl)

		testResult := httpSimple("GET", rurl, []byte(""), "application/json")
		//然后将这个结果提交到服务端进行保存
		httpSimple("POST", "http://127.0.0.1:9012/upload/stop/result", testResult, "application/json")
		log.Println("==========================================================================stop")
	})

	boomer.Events.Subscribe("boomer:quit", func() {
		log.Println("==========================================================================quit")
	})

	task := &boomer.Task{
		Name:   "loadRun",
		Weight: 100,
		Fn:     boomerWork,
	}

	globalBoomer.Run(task)
	waitForQuit()
	//以下为调试代码，仅做备用
	/*
		hd := RequestHeaderData{}
		hd.HeaderName = "Content-Type"
		hd.HeaderValue = "application/json"

		hds := []RequestHeaderData{hd, hd}

		//请求的主体内容

		hr := RequestBodyData{}
		hr.Method = "GET"
		hr.Url = "http://172.22.23.148:9001/get?ip=172.22.186.233"
		hr.PostBody = ""

		//应该是一个list
		hr.Header_datas = hds
		hr.ContentType = "application/json"
		hr.DisableKeepalive = false
		hr.Disable_response = true
		hr.Expect_code = 200
		hr.Expect_string = ""
		hrs := []RequestBodyData{hr}
		//构造的主体内容
		td_local := TaskData{}
		td_local.Task_name = "testing"
		td_local.Request_datas = hrs

		TD = td_local

		//log.Println(TD)



		//boomerWork()

		//log.Println(TD)
		//httpSimple(method string, url string, postBody []byte, contentType string)
		d := httpSimple("GET", "http://127.0.0.1:9012/load/task", []byte(""), "application/json")

		log.Println(initRequestData(d))

		task := &boomer.Task{
			Name:   "loadRun",
			Weight: 100,
			Fn:     boomerWork,
		}

		boomer.Run(task)
	*/

}
